// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//

// NOTE: API is EXPERIMENTAL and will change without going through a
// deprecation cycle.

#pragma once

#include <nebula/compute/type_fwd.h>
#include <turbo/meta/compare.h>
#include <turbo/utility/status.h>
#include <nebula/types/type_fwd.h>
#include <turbo/base/macros.h>

namespace nebula::compute {

    /// \addtogroup compute-functions
    /// @{

    /// \brief Extension point for defining options outside libarrow (but
    /// still within this project).
    class TURBO_EXPORT FunctionOptionsType {
    public:
        virtual ~FunctionOptionsType() = default;

        [[nodiscard]] virtual const char *type_name() const = 0;

        [[nodiscard]] virtual std::string stringify(const FunctionOptions &) const = 0;

        [[nodiscard]] virtual bool compare(const FunctionOptions &, const FunctionOptions &) const = 0;

        [[nodiscard]] virtual turbo::Result<std::shared_ptr<Buffer>> serialize(const FunctionOptions &) const;

        [[nodiscard]] virtual turbo::Result<std::unique_ptr<FunctionOptions>> deserialize(BufferSpan buffer) const;

        [[nodiscard]]  virtual std::unique_ptr<FunctionOptions> copy(const FunctionOptions &) const = 0;
    };

    /// \brief Base class for specifying options configuring a function's behavior,
    /// such as error handling.
    class TURBO_EXPORT FunctionOptions : public turbo::EqualityComparable<FunctionOptions> {
    public:
        virtual ~FunctionOptions() = default;

        [[nodiscard]] const FunctionOptionsType *options_type() const { return options_type_; }

        [[nodiscard]] const char *type_name() const { return options_type()->type_name(); }

        [[nodiscard]] bool equals(const FunctionOptions &other) const;

        [[nodiscard]]  std::string to_string() const;

        [[nodiscard]] std::unique_ptr<FunctionOptions> copy() const;

        /// \brief serialize an options struct to a buffer.
        [[nodiscard]] turbo::Result<std::shared_ptr<Buffer>> serialize() const;

        /// \brief deserialize an options struct from a buffer.
        /// Note: this will only look for `type_name` in the default FunctionRegistry;
        /// to use a custom FunctionRegistry, look up the FunctionOptionsType, then
        /// call FunctionOptionsType::deserialize().
        static turbo::Result<std::unique_ptr<FunctionOptions>> deserialize(
                const std::string &type_name, BufferSpan  buffer);

    protected:
        explicit FunctionOptions(const FunctionOptionsType *type) : options_type_(type) {}

        const FunctionOptionsType *options_type_;
    };

    TURBO_EXPORT void print_to(const FunctionOptions &, std::ostream *);

    /// @}

}  // namespace nebula::compute
